/*
 * author: Kai Jiang
 * Date: Feb 27 2014
 * CS202
 * Assignment 3
 * purpose: complete member functions in class editor.h
 */

#include <iostream>
#include <cstdio>
#include <cstring>
#include "editor.h"
using namespace std;


/*class word
 * member functions
 *
 *
 */

//constructor with no agrument
word::word():w(NULL),len(0){
}

//constructor with char pointer
word::word(char* t){
	len = strlen(t);
	w = new char[len];
	strcpy(w, t);
}

//constructor to copy a word
word::word(const word& cp){
	if (cp.len == 0)
		w = NULL;
	else{
		w = new char [cp.len+1];
		strcpy(w,cp.w);
		len = cp.len;
	}
}

//destructor
word::~word(){
	delete [] w;
	len = 0;
}

//judge two words are same
bool word::operator == (const word& s) const{
	return !strcmp(this->w, s.w);
}

//judge two words are different
bool word::operator != (const word& s) const{
	return strcmp(this->w, s.w);
}

//copy existing word to a new word
word& word::operator = (const word& s2){
	if (this == &s2)
		return *this;
	if (w)
		delete [] w;
	w = new char [s2.len+1];
	strcpy(w,s2.w);
	len = s2.len;
	return *this;
}

//connect word return word
word word::operator + (const word& s) const{
	char* temp = new char[len+s.len+1];
	strcpy(temp, w);
	strcat(temp, s.w);
	return word(temp);
}

//connect pointer return word
word word::operator + (char* t){
	char* temp = new char[len+strlen(t)+1];
	strcpy(temp,w);
	strcat(temp,t);
	return word(temp);
}

//append the word
word& word::operator += (const word& s){
	len += s.len;
	char* temp = new char[len+1];
	strcpy(temp,w);
	strcat(temp,s.w);
	w = temp;
	return *this;
}

//append the char pointer
word& word::operator += (char* t){
	len += strlen(t);
	char* temp = new char[len+1];
	strcpy(temp,w);
	strcat(temp,t);
	w = temp;
	return *this;
}

//connect two words
word operator + (const word& wd1, const word& wd2){
	char* temp = new char[wd1.len+wd2.len+1];
	strcpy(temp,wd1.w);
	strcat(temp,wd2.w);
	return word(temp);
}

//connect word (first operand) and char pointer(second operand)
word operator + (const word& wd1, char* t){
	char* temp = new char[wd1.len+strlen(t)+1];
	strcpy(temp,wd1.w);
	strcat(temp,t);
	return word(temp);
}

//connect char pointer(first operand) and word (second operand)
word operator + (char*t ,const word& wd1){
	char* temp = new char[wd1.len+strlen(t)+1];
	strcpy(temp,t);
	strcat(temp,wd1.w);
	return word(temp);
}


//input the word and allocate memory
istream& operator >> (istream& in, word& w){
	char tmp[100];
	char next_char;
	in >> tmp;
	w.len = strlen(tmp);
	w.w = new char[w.len+1];
	strcpy(w.w,tmp);
	return in;
}

//output the word
ostream& operator << (ostream& o, const word& w){
	o << w.w;
	return o;
}


//return the number of characters in word
int word::length() const{
	return len;
}

//capitalize the word
void word::capital(){
	if (len)
		if( w[0] >= 'a' && w[0] <= 'z' ){
			w[0] -= 'a' - 'A';
		}
}


//if the word is ending with comma or semicolon return true
bool word::endingCommas() const{
	if ( w[len-1] == ',' || w[len-1] == ';')
		return true;
	else
		return false;
}

/* class LLL
 * Linear Linked List
 * member functions
 *
 *
 */


//constructor
LLL::LLL(){
	tail = NULL;
	ptr = NULL;
}

//destructor
LLL::~LLL(){
	delete tail;
	delete ptr;
}

/* class sentence
 * member functions
 *
 *
 */

//constructor without argument
sentence::sentence():head(NULL){
	tail = NULL;
	cntWord = 0;
	cntComma = 0;
 }

//constructor to copy one sentence
sentence::sentence(const sentence& l){
	if (!l.head)
		head = tail = ptr = NULL;
	else{
		head = new node;
		head -> wd = l.head -> wd;

		node* dest = head;
		node* source = l.head -> next;
		while (source){
			dest -> next = new node;
			dest = dest -> next;
			dest -> wd = source -> wd;
			source = source -> next;
		}
		dest -> next = NULL;
		tail = dest;
		ptr = head;
	}
	cntWord = l.cntWord;
	cntComma = l.cntComma;
}

//constructor to construct a sentence with one word
sentence::sentence(const word& wdd){
	if ( !wdd.length() )
		head = tail = ptr = NULL;
	else{
		head = new node;
		head -> wd = wdd;
		head -> next = NULL;
		tail = head;
	}
	cntWord = 1;
	if (wdd.endingCommas())
		cntComma = 1;
	else
		cntComma = 0;
}

//destructor
sentence::~sentence(){
	node* cur;
	while (head){
		cur = head -> next;
		delete head;
		head = cur;
	}
	ptr = tail = NULL;
}

//copy sentence
sentence& sentence::operator = (const sentence& l){
	if ( this == &l )
		return *this;
	node* cur;

	//If there is a sentence, delete its words
	while( head ){
		cur = head -> next;
		delete head;
		head = cur;
	}

	if (!l.head)
		head = tail = ptr = NULL;
	else{
		head = new node;
		head -> wd = l.head -> wd;

		node* dest = head;
		node* source = l.head -> next;
		while (source){
			dest -> next = new node;
			dest = dest -> next;
			dest -> wd = source -> wd;
			source = source -> next;
		}
		dest -> next = NULL;
		tail = dest;
		ptr = head;
	}
	return *this;
}

//copy one word to a sentence
sentence& sentence::operator = (const word& wdd){
	if ( this -> head -> next == NULL && this -> head -> wd == wdd ){
		return *this;
	}
	node* cur;

	//If there is a sentence, delete its words
	while( head ){
		cur = head -> next;
		delete head;
		head = cur;
	}
	if ( !wdd.length() )
		head = tail = ptr = NULL;
	else{
		head = new node;
		head -> wd = wdd;
		head -> next = NULL;
		tail = head;
	}	
	return *this;
}

//output a sentence
ostream& operator << (ostream& out, const sentence& l){
	node* cur = l.head;
	while (cur){
		if ( cur -> next == NULL)
			out << cur -> wd << "  ";
		else
			out << cur -> wd << ' ';
		cur = cur -> next;
	}
	return out;
}

//input a sentence
istream& operator >> (istream& in, sentence& l){
	node* cur = l.tail;
	if (!cur) {		//empty sentence
		l.head = cur = new node;
		in >> l.head -> wd;
		l.tail = l.ptr = l.head;
		l.head -> next = NULL;
	}
	node * savelist = l.tail->next;
	char next_char;
	while((next_char = in.peek()) != '\n' && next_char != EOF){
		cur->next = new node;
		l.cntWord++ ;		// count words in sentence
		cur = cur->next;
		in >>cur-> wd;
	}
	cur->next = savelist; //ptr = cur;
	if (!savelist) l.tail = cur;
	return in;
}

//judge two sentences are same( every words are same)
bool sentence::operator == (const sentence& s) const{
	node* first = head;
	node* second = s.head;
	while(first && second && first -> wd == second -> wd){
		first = first -> next;
		second = second -> next;
	}
	if (first || second)
		return false;
	else
		return true;
}


//judge two sentences are different
bool sentence::operator != (const sentence& s) const{
	return !(*this == s);
}

//connect two sentences
sentence operator + (const sentence& s1, const sentence& s2){
	sentence temp(s1);
	if (!temp.head)
		temp = s2;
	else{
		node* dest = temp.tail;
		node* source = s2.head;
		while (source){
			dest -> next = new node;
			dest = dest -> next;
			dest -> wd = source -> wd;
			source = source -> next;
		}
		dest -> next = NULL;
		temp.tail = dest;
		temp.ptr = temp.head;
	}
	return temp;
}

sentence operator + (const sentence& s, const word &wd){
	sentence temp(s);
	if (!temp.head)
		temp = wd;
	else{
		node* dest = temp.tail;
		dest -> next = new node;
		dest = dest -> next;
		dest -> wd = wd;
		dest -> next = NULL;
		temp.tail = dest;
		temp.ptr = temp.head;
	}
	return temp;
}

sentence operator + (const word & wd, const sentence & s){
	sentence temp;
	temp = wd;
	node* dest = temp.tail;
	node* source = s.head;
	while (source){
		dest -> next = new node;
		dest = dest -> next;
		dest -> wd = source -> wd;
		source = source -> next;
	}
	dest -> next = NULL;
	temp.tail = dest;
	temp.ptr = temp.head;
}

//append one sentence to a existing sentence
sentence& sentence::operator += (const sentence& s){
	if (!head)
		*this = s;
	else{
		node* dest = tail;
		node* source = s.head;
		while(source){
			dest -> next = new node;
			dest = dest -> next;
			dest -> wd = source -> wd;
			source = source -> next;
		}
		dest -> next = NULL;
		tail = dest;
	}
	return *this;
}

//append a word to existing sentence
sentence& sentence::operator += (const word& wd){
	if (!head)
		*this = wd;
	else{
		node* dest = this -> tail;
		dest -> next = new node;
		dest = dest -> next;
		dest -> wd = wd;
		dest -> next = NULL;
		this -> tail = dest;
		this -> ptr = this -> head;
	}
}

//return i th word in a sentence
word& sentence::operator [] (int index) const{
	node* cur = head;
	for(int i=0; i<index && cur; ++i){
		cur = cur -> next;
	}
	if( !cur ){
		word* temp = new word;
		return *temp;
	}
	return cur -> wd;
}

//capitalize first word in sentence
void sentence::capitalization(){
	if ( !head )
		return;
	else{
		head -> wd.capital(); 
	}
}

//output warning information
void sentence::warningLong(){
	for(int i = 0; i< cntWord ; ++i)
		if ( (*this)[i].endingCommas() )
			cntComma++;
	if (cntComma <= 2 && cntWord >= 10)
		cout << endl << "Waring: " << "Words: "<< cntWord << " ~Long sentence!!~" << endl; 
}

//return the number of words in a sentence
int sentence::length() const {
	return cntWord;
}